# 闭包
# 条件
# 1.函数嵌套
# 2.内层函数使用外层函数的局部变量
# 3.外层函数的返回值是内层函数的函数名
# def outer():
#     n = 10
#     def inner():
#         print(n)
#     return inner
# print(outer())      #返回的是内部函数的内存地址
# 第一种写法
# outer()()
# 第二种写法
# ot = outer()
# ot()

# def outer(m):
#     n = 10
#     def inner():
#         print(n + m)
#     return inner
# outer(5)()

# 每次开启内函数都在使用同一份闭包变量
# def outer(o):
#     def inner(i):
#         print("inner:", i)
#         return i + o
#     return inner
# ot = outer(10)
# # 调用inner
# # 第一次调用：
# print(ot(20))
# # 第二次调用：
# print(ot(30))

# 装饰器
# def test(fn):
#     print("原功能")
#     fn()
# def test2():
#     print("新功能")
# test(test2)
# 条件：
#     1.不修改源程序或函数的代码
#     2.不改变函数或程序的调用方法

# 标准版装饰器
# def outer(fn):
#     def inner():
#         print("原功能")
#         fn()
#     return inner
# def new1():
#     print("新功能1")
# def new2():
#     print("新功能2")
# ot1 = outer(new1)
# ot1()
# ot2 = outer(new2)
# ot2()

# 语法糖
# def outer(fn):
#     def inner():
#         print("原功能")
#         fn()
#     return inner
#  #装饰器名称后面不要加上()，不加括号是引用，加括号是调用函数，返回该函数要返回的值
# @outer   #不要和下面的函数有空行
# def new1():
#     print("新功能1")
# new1()

# 被装饰的函数有参数
# def outer(fn):
#     def inner(*args, **kwargs):
#         print("原功能")
#         print(f"参数：{args}")
#         print(f"参数：{kwargs}")
#         fn()
#     return inner
# @outer
# def new1():
#     print("新功能1")
# new1(name = 1)

# 多个装饰器
# def decorator1(func):
#     def wrapper(*args, **kwargs):
#         print("decorated 1")
#         return "decorated 1 " + func(*args, **kwargs) + " decorated 1"
#     return wrapper
# def decorator2(func):
#     def wrapper(*args, **kwargs):
#         print("decorated 2")
#         return "decorated 2 " + func(*args, **kwargs) + " decorated 2"
#     return wrapper
# @decorator1
# @decorator2
# def func1(*args, **kwargs):
#     return " func1 "
# print(func1())